/* Valuation.ado (STATA)
	Asset prices without special demand.
	by Ralph Koijen & Motohiro Yogo */

#delimit ;

program Valuation;
args n y t;

di `y';


/* Load data */

u "../3 Estimation/Consumption`n'" if year==`y', clear; 

/* Demand shifters */

gen shifter = b_cons+eps;

qui foreach var of varlist $macro $bilateral $dummies {;
	replace shifter = shifter+b_`var'*`var';
};

/* Aggregate demand shifters */

gen shifterA = bA_cons+epsA;

/* Construct latent demand including year fixed effects */

gen epsFE = eps;

qui foreach var of varlist Iyear_* {;
	replace epsFE = epsFE+b_`var'*`var';
};

/* Estimate mean latent demand for US assets, excluding own holdings */

if `n'==0 {;
	egen Meps_USA = mean(epsFE*(counterpart=="USA" & type==`t' & !Iown)), by(counterpart type Iown);
};
else if `n'==1 {;
	gen Meps_USA = epsFE*(counterpart=="USA" & type==`t' & !Iown);
};


/* STEP 0: Check code
   STEP 1-6: No special demand by country group */

qui forval i = 0/6 {;

	/* No special demand */

	gen shifterCF = shifter if country_group>`i'-1;
	replace shifterCF = shifter-Meps_USA if country_group<=`i'-1;

	/* Initial guess for prices */

	if `i'==0 {;
		gen LfxCF = Lfx;
		gen LmbCF = Lmb;

		gen shiftCF = 0;
	};
	else {;
		gen LfxCF = Lfx`=`i'-1';
		gen LmbCF = Lmb`=`i'-1';

		gen shiftCF = shift`=`i'-1';
	};

	/* Solve for prices */

	forval s = 1/$Nstep {;

		/* Expected returns in USD */

		gen EretCF = c_Lmb*LmbCF+c_Lrealfx*(LfxCF-Lrelpi)+c_cons;

		/* Adjust expected returns to local currency */

		egen Eret_LCU = total(EretCF*(type==1 & Iycounterpart)), missing by(country);

		replace EretCF = EretCF-Eret_LCU;

		drop Eret_LCU;

		/* Construct inner portfolio weights */

		gen delta = exp(b_Eret*EretCF+shifterCF-shiftCF);

		egen Sdelta = total(delta), missing by(country type);
		replace Sdelta = 1+Sdelta;

		gen weight = delta/Sdelta;

		drop EretCF delta;

		/* Construct outer portfolio weights */

		gen Sdelta1 = Sdelta^bA_LSrw1*exp(shifterA) if type==1;
		replace Sdelta1 = Sdelta^bA_LSrw2*exp(shifterA) if type==2;
		replace Sdelta1 = Sdelta^bA_LSrw3*exp(shifterA) if type==3;

		egen Sdelta2 = total(Sdelta1*Iycountry), missing by(country);

		gen weightA = Sdelta1/Sdelta2;

		drop Sdelta*;

		/* Construct wealth before portfolio choice */

		egen wealth1CF = total(amount*exp(LmbCF-Lmb+LfxCF-Lfx)), missing by(country);
		replace wealth1CF = wealth1CF+outside;

		sort country wealth1CF;
		by country: replace wealth1CF = wealth1CF[1];

		/* Construct wealth after portfolio choice */

		egen Tweight = total(weight*weightA), missing by(country);

		gen wealth2CF = outside/(1-Tweight);

		drop Tweight;

		/* Check convergence of wealth */

		gen gap_W = ln(wealth2CF)-ln(wealth1CF) if type==1 & Iycountry;

		sum gap_W;
		local gap_W = max(abs(r(min)),abs(r(max)));

		drop wealth1CF;

		/* Update demand shifters */

		replace shiftCF = shiftCF+$step_W*gap_W if !missing(gap_W);

		sort country gap_W;
		by country: replace shiftCF = shiftCF[1];

		drop gap_W;

		/* Construct demand */

		egen demand = total(wealth2CF*weight*weightA), missing by(counter_euro type);

		drop weight* wealth2CF;

		/* Check convergence of demand */

		gen gap = ln(demand)-(LmbCF+LfxCF+ln(Qmarket)) if Iycounter_euro;

		sum gap if counter_euro!="USA" | type!=1;
		local gap = max(abs(r(min)),abs(r(max)));

		sum gap if counter_euro=="USA" & type==1;
		local gap_US = max(abs(r(min)),abs(r(max)));

		drop demand;

		/* Update exchange rates */

		replace LfxCF = LfxCF+$step_fx*gap/(1-b_Eret*c_Lrealfx) if counter_euro!="USA" & type==1;

		sort counter_euro type gap;
		by counter_euro type: replace LfxCF = LfxCF[1];

		gsort counterpart type -Iycounterpart;
		by counterpart: replace LfxCF = LfxCF[1];

		/* Update asset prices */

		replace LmbCF = LmbCF+$step_mb*gap/(1-b_Eret*c_Lmb) if type!=1;

		sort counter_euro type gap;
		by counter_euro type: replace LmbCF = LmbCF[1];

		drop gap;

		/* Exit if converged */

		if `gap'<$Mgap | `s'==$Nstep {;

			/* Summary */

			nois di `i' _skip(5) `s' _skip(5) `gap_W' _skip(5) `gap' _skip(5) `gap_US';

			/* Save estimates */

			gen Lfx`i' = LfxCF;
			gen Lmb`i' = LmbCF;
			gen yield`i' = -LmbCF/maturity;
			gen Eret`i' = c_Lmb*LmbCF+c_Lrealfx*(LfxCF-Lrelpi)+c_cons;

			gen shift`i' = shiftCF;

			continue, break;
		};
	};

	drop *CF;
};

/* Fix variables */

qui replace Name = "Euro" if counter_euro=="EUR";

qui replace Eret = c_Lmb*Lmb+c_Lrealfx*(Lfx-Lrelpi)+c_cons;

/* Keep estimates only */

qui keep if Iycounter_euro;

keep year counter_euro Name type market Lfx* Lmb* yield* Eret*;

/* Construct variables */

gen byte Ctype = `t';

/* Construct changes */

qui foreach var of varlist Lfx Lmb yield Eret {;
	gen D`var' = `var'6-`var';
	gen D`var'1 = `var'1-`var';

	forval i = 2/6 {;
		gen D`var'`i' = `var'`i'-`var'`=`i'-1';
	};
};

/* Label variables */

order Ctype, after(type);
order Lfx* Lmb* yield* DLfx* DLmb* Dyield* DEret*, after(market);

label var Ctype		"Counterfactual for this type";

label var Lfx0		"Exchange rate: Check code";
label var Lmb0		"Price: Check code";
label var yield0	"Yield: Check code";
label var Eret0		"Expected return: Check code";

label var DLfx		"Exchange rate change";
label var DLmb		"Price change";
label var Dyield	"Yield change";
label var DEret		"Expected return change";

forval i = 1/6 {;
	label var Lfx`i'	"Exchange rate: country_group==`=`i'-1'";
	label var Lmb`i'	"Price: country_group==`=`i'-1'";
	label var yield`i'	"Yield: country_group==`=`i'-1'";
	label var Eret`i'	"Expected return: country_group==`=`i'-1'";

	label var DLfx`i'	"Exchange rate change: country_group==`=`i'-1'";
	label var DLmb`i'	"Price change: country_group==`=`i'-1'";
	label var Dyield`i'	"Yield change: country_group==`=`i'-1'";
	label var DEret`i'	"Expected return change: country_group==`=`i'-1'";
};

/* Save estimates */

if `y'>2003 | `t'!=1 {;
	qui append using Valuation`n';
};

sort year counter_euro type;

qui save Valuation`n', replace;

end;
